/*
 * Eugen Stoian <stoian.e@gmail.com> 2010
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "GLWidget.h"
#include <QtGui>
#include <QtOpenGL>
#include "PlotableObject3D.h"
#include <cmath>

 GLWidget::GLWidget(QWidget *parent)
         : QGLWidget(parent),_object(0){
     _xRot = 0;
     _yRot = 0;
     _zRot = 0;
 }
 void GLWidget::setObject(PlotableObject3D* object){
     _object = object;
     if(_object){
         _object->compute();
     }
 }

 GLWidget::~GLWidget()
 {
     if(_object){
        makeCurrent();
        makeCurrent();
        glDeleteLists(_object->id(),1);
        _object->reset();
    }
 }

 QSize GLWidget::minimumSizeHint() const
 {
     return QSize(300, 300);
 }

 QSize GLWidget::sizeHint() const
 {
     return QSize(600, 600);
 }

 void GLWidget::setXRotation(int angle)
 {
     normalizeAngle(&angle);
     if (angle != _xRot) {
         _xRot = angle;
         emit xRotationChanged(angle);
         updateGL();
     }
 }

 void GLWidget::setYRotation(int angle)
 {
     normalizeAngle(&angle);
     if (angle != _yRot) {
         _yRot = angle;
         emit yRotationChanged(angle);
         updateGL();
     }
 }

 void GLWidget::setZRotation(int angle)
 {
     normalizeAngle(&angle);
     if (angle != _zRot) {
         _zRot = angle;
         emit zRotationChanged(angle);
         updateGL();
     }
 }

 void GLWidget::initializeGL()
 {
     glClearColor(1.0,1.0,1.0,0.0);
     glShadeModel(GL_FLAT);
     glEnable(GL_DEPTH_TEST);
 }

 void GLWidget::paintGL()
 {
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity();
     if(_object){
        gluLookAt(_object->xCenter(),_object->yCenter(),_object->zMin()-2*_object->radius(),_object->xCenter(),_object->yCenter(),_object->zCenter(),0,1,0);
        glTranslated(_object->xCenter(),_object->yCenter(),_object->zCenter());
        glRotated(_xRot / 16.0, 1.0, 0.0, 0.0);
        glRotated(_yRot / 16.0, 0.0, 1.0, 0.0);
        glRotated(_zRot / 16.0, 0.0, 0.0, 1.0);
        glTranslated(-_object->xCenter(),-_object->yCenter(),-_object->zCenter());
        glColor3f(1.0f,0.0f,0.0f);
        glBegin(GL_LINES);
            glVertex3d(_object->xMin(),_object->yMin(),_object->zMin());
            glVertex3d(_object->xMax(),_object->yMin(),_object->zMin());
            glVertex3d(_object->xMin(),_object->yMin(),_object->zMin());
            glVertex3d(_object->xMin(),_object->yMax(),_object->zMin());
            glVertex3d(_object->xMin(),_object->yMin(),_object->zMin());
            glVertex3d(_object->xMin(),_object->yMin(),_object->zMax());
        glEnd();
        QString O = "("+QString::number(_object->xMin())+","+QString::number(_object->yMin())+","+QString::number(_object->zMin())+")";
        QString X = "X  ("+QString::number(_object->xMax())+","+QString::number(_object->yMin())+","+QString::number(_object->zMin())+")";
        QString Y = "Y  ("+QString::number(_object->xMin())+","+QString::number(_object->yMax())+","+QString::number(_object->zMin())+")";
        QString Z = "Z  ("+QString::number(_object->xMin())+","+QString::number(_object->yMin())+","+QString::number(_object->zMax())+")";
        renderText(_object->xMin(),_object->yMin(),_object->zMin(),O);
        renderText(_object->xMax(),_object->yMin(),_object->zMin(),X);
        renderText(_object->xMin(),_object->yMax(),_object->zMin(),Y);
        renderText(_object->xMin(),_object->yMin(),_object->zMax(),Z);

        _object->display();
    }
 }

 void GLWidget::resizeGL(int width, int height)
 {
    glViewport(0, 0, width, height);
    double aspect = (double)width/(double)height;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if(_object)
    {
        GLfloat fogColor[4] = { 1.0, 1.0, 1.0, 0.95};
        gluPerspective(65,aspect,_object->radius(),0.01+4*_object->radius());
        glFogf(GL_FOG_MODE,GL_LINEAR);
        glFogf(GL_FOG_START,0.1*_object->radius());
        glFogf(GL_FOG_END,4*_object->radius());
        glFogfv(GL_FOG_COLOR, fogColor);
        glEnable(GL_FOG);
    }
     else
    {
        glFrustum(-1,1,-1,1,0.1,2.1);
    }

     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
 }

 void GLWidget::mousePressEvent(QMouseEvent *event)
 {
     _lastPos = event->pos();
 }

 void GLWidget::mouseMoveEvent(QMouseEvent *event)
 {
     int dx = event->x() - _lastPos.x();
     int dy = event->y() - _lastPos.y();

     if (event->buttons() & Qt::LeftButton) {
         setXRotation(_xRot + 8 * dy);
         setYRotation(_yRot - 8 * dx);
     } else if (event->buttons() & Qt::RightButton) {
         setXRotation(_xRot + 8 * dy);
         setZRotation(_zRot - 8 * dx);
     }
     _lastPos = event->pos();
 }


 void GLWidget::normalizeAngle(int *angle)
 {
     while (*angle < 0)
         *angle += 360 * 16;
     while (*angle > 360 * 16)
         *angle -= 360 * 16;
 }
